﻿using System;
using System.Globalization;

namespace XNET.Extension
{
    /// <summary>
    /// 日期扩展
    /// </summary>
    public static class DatetimeExtension
    {
        /// <summary>
        /// 获取每月第一天
        /// </summary>
        /// <param name="dt">日期</param>
        /// <returns></returns>
        public static DateTime FirstDayOfMonth(this DateTime dt)
        {
            return dt.AddDays(1 - dt.Day);
        }

        /// <summary>
        /// 获取每月的最后一天
        /// </summary>
        /// <param name="dt">日期</param>
        /// <returns></returns>
        public static DateTime LastDayOfMonth(this DateTime dt)
        {
            return dt.AddMonths(1).AddDays(1 - dt.Day - 1);
        }

        /// <summary>
        /// 添加指定数量星期
        /// </summary>
        /// <param name="dt">日期</param>
        /// <param name="NumberOfWeek">星期数量</param>
        /// <returns></returns>
        public static DateTime AddWeeks(this DateTime dt, int NumberOfWeek)
        {
            return dt.AddDays(NumberOfWeek * 7);
        }

        /// <summary>
        /// 计算年龄
        /// </summary>
        /// <param name="dt">日期</param>
        /// <param name="CalculateFrom">计算开始日期</param>
        /// <returns>年龄</returns>
        public static int Age(this DateTime dt, DateTime CalculateFrom = default(DateTime))
        {
            if (CalculateFrom == default(DateTime))
            {
                CalculateFrom = DateTime.Now;
            }
            return (CalculateFrom - dt).Years();
        }

        /// <summary>
        /// 比较时间，确定当前时间在什么时间段
        /// </summary>
        /// <param name="Date">当前日期</param>
        /// <param name="Comparison">比较类型</param>
        /// <returns></returns>
        public static bool Is(this DateTime Date, DateCompare Comparison)
        {
            if (Comparison.HasFlag(DateCompare.InFuture) && DateTime.Now >= Date)
            {
                return false;
            }
            if (Comparison.HasFlag(DateCompare.InPast) && DateTime.Now <= Date)
            {
                return false;
            }
            if (Comparison.HasFlag(DateCompare.Today) && DateTime.Today != Date.Date)
            {
                return false;
            }
            if (Comparison.HasFlag(DateCompare.WeekDay) && ((int)Date.DayOfWeek == 6 || (int)Date.DayOfWeek == 0))
            {
                return false;
            }
            if (Comparison.HasFlag(DateCompare.WeekEnd) && (int)Date.DayOfWeek != 6 && (int)Date.DayOfWeek != 0)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 获取本地时区
        /// </summary>
        /// <param name="Date">当前时间</param>
        /// <returns></returns>
        public static TimeZoneInfo LocalTimeZone(this DateTime Date)
        {
            return TimeZoneInfo.Local;
        }

        /// <summary>
        /// 将日期转换到一个特定的时区
        /// </summary>
        /// <param name="Date">当前时间</param>
        /// <param name="TimeZone">要转换的时区</param>
        /// <returns></returns>
        public static DateTime To(this DateTime Date, TimeZoneInfo TimeZone)
        {
            return TimeZoneInfo.ConvertTime(Date, TimeZone);
        }

        /// <summary>
        /// 返回纪元时间以来的天数 (默认unix纪元 1/1/1970)
        /// </summary>
        /// <param name="Date">时间</param>
        /// <param name="Epoch">纪元(默认unix纪元1/1/1970)</param>
        /// <returns></returns>
        public static int To(this DateTime Date, DateTime Epoch = default(DateTime))
        {
            Epoch = Epoch.Check(x => x != default(DateTime), () => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            return (int)((Date.ToUniversalTime() - Epoch).Ticks / TimeSpan.TicksPerSecond);
        }

        /// <summary>
        /// 返回纪元时间 (默认unix纪元 1/1/1970)
        /// </summary>
        /// <param name="Date">天数</param>
        /// <param name="Epoch">纪元(默认unix纪元1/1/1970)</param>
        /// <returns></returns>
        public static DateTime To(this int Date, DateTime Epoch = default(DateTime))
        {
            Epoch = Epoch.Check(x => x != default(DateTime), () => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            return new DateTime((Date * TimeSpan.TicksPerSecond) + Epoch.Ticks, DateTimeKind.Utc);
        }

        /// <summary>
        /// 返回纪元时间 (默认unix纪元 1/1/1970)
        /// </summary>
        /// <param name="Date">天数</param>
        /// <param name="Epoch">纪元(默认unix纪元1/1/1970)</param>
        /// <returns></returns>
        public static DateTime To(this long Date, DateTime Epoch = default(DateTime))
        {
            Epoch = Epoch.Check(x => x != default(DateTime), () => new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            return new DateTime((Date * TimeSpan.TicksPerSecond) + Epoch.Ticks, DateTimeKind.Utc);
        }

        /// <summary>
        /// 获取当前UTC时区
        /// </summary>
        /// <param name="Date">当前时间</param>
        /// <returns></returns>
        public static double UTCOffset(this DateTime Date)
        {
            return (Date - Date.ToUniversalTime()).TotalHours;
        }

        /// <summary>
        /// 格式化日期
        /// </summary>
        /// <param name="date">日期</param>
        /// <param name="format">格式化方式</param>
        /// <returns></returns>
        public static string Format(this DateTime date, DateTimeFormatEnum format)
        {
            return date.ToString(format.ToString());
        }
    }
    /// <summary>
    /// 时间格式化枚举
    /// </summary>
    public enum DateTimeFormatEnum
    {
        /// <summary>
        /// 2005-11-5
        /// </summary>
        d = 0,
        /// <summary>
        /// 2005年11月5日
        /// </summary>
        D = 1,
        /// <summary>
        /// 2005年11月5日 14:23
        /// </summary>
        f = 2,
        /// <summary>
        /// 2005年11月5日 14:23:23
        /// </summary>
        F = 3,
        /// <summary>
        /// 2005-11-5 14:23
        /// </summary>
        g = 4,
        /// <summary>
        /// 2005-11-5 14:23:23
        /// </summary>
        G = 5,
        /// <summary>
        /// 2005-11-05T14:23:23
        /// </summary>
        s = 6,
        /// <summary>
        /// 11月5日
        /// </summary>
        M = 7,
        /// <summary>
        /// Sat, 05 Nov 2005 14:23:23 GMT
        /// </summary>
        R = 8,
        /// <summary>
        /// 14:23
        /// </summary>
        t = 9,
        /// <summary>
        /// 14:23:23
        /// </summary>
        T = 10,
        /// <summary>
        /// 2005-11-05 14:23:23Z
        /// </summary>
        u = 11,
        /// <summary>
        /// 2005年11月5日 6:23:23
        /// </summary>
        U = 12,
        /// <summary>
        /// 2005年11月
        /// </summary>
        Y = 13,
    }

    /// <summary>
    /// 时间段
    /// </summary>
    public enum TimeFrame
    {
        /// <summary>
        /// 天
        /// </summary>
        Day,
        /// <summary>
        /// 周
        /// </summary>
        Week,
        /// <summary>
        /// 月
        /// </summary>
        Month,
        /// <summary>
        /// 季度
        /// </summary>
        Quarter,
        /// <summary>
        /// 年
        /// </summary>
        Year
    }

    /// <summary>
    /// 日期类型比较
    /// </summary>
    [Flags]
    public enum DateCompare
    {
        /// <summary>
        /// 今天之后
        /// </summary>
        InFuture = 1,
        /// <summary>
        /// 今天之前
        /// </summary>
        InPast = 2,
        /// <summary>
        /// 今天
        /// </summary>
        Today = 4,
        /// <summary>
        /// 工作日
        /// </summary>
        WeekDay = 8,
        /// <summary>
        /// 周末
        /// </summary>
        WeekEnd = 16
    }
}
